package org.nicocube.airain.app.client.ui;

import java.util.Map;

import org.nicocube.airain.app.client.AirainApp;
import org.nicocube.airain.app.client.AppGCServiceAsync;
import org.nicocube.airain.app.client.domain.AppGameCharacter;
import org.nicocube.airain.common.client.AirainMessenger;
import org.nicocube.airain.domain.client.character.Gender;
import org.nicocube.airain.domain.client.exception.GCMaxNumberCreateException;
import org.nicocube.airain.domain.client.exception.GCNameDuplicateCreateException;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

public abstract class CreateGameCharacterPanel extends Composite {

	public static interface I18nConstants extends Constants,AirainApp.I18nConstants {
		@DefaultStringValue("Create a new Character")
		String createDescription();

		@DefaultStringValue("Name:")
		String nameLabel();

		@DefaultStringValue("Gender:")
		String genderLabel();

		@DefaultStringValue("Create")
		String createButton();

		@DefaultStringValue("Please assign a gender.")
		String genderUnassigned();

		@DefaultStringValue("Close.")
		String dialogBoxClose();

		@DefaultStringValue("Impossible creating a Character with existing name for a given account.")
		String impossibleSameName();

		@DefaultStringValue("Impossible creating more than three Characters for a given account.")
		String maxNumberExceeded();

		@DefaultStringValue("Error while loading.")
		String errorOnLoading();
	}

	private I18nConstants constants;

	private DisclosurePanel widget;

	private final AppGCServiceAsync appGcServiceAsync;

	private final AirainMessenger messenger;

	private DialogBox genderUnassignedDialogBox;

	public CreateGameCharacterPanel(AppGCServiceAsync appGcServiceAsync, AirainMessenger messenger) {
		constants = GWT.create(I18nConstants.class);
		this.appGcServiceAsync = appGcServiceAsync;
		this.messenger = messenger;
		widget = new DisclosurePanel(constants.createDescription());
		initWidget(widget);
	}

	@Override
	protected void onLoad() {
		super.onLoad();

		final HorizontalPanel genderPanel = new HorizontalPanel();

		Map<String, String> genderOptions = constants.genders();

		for (Gender g : Gender.values()) {
			RadioButton rb = new RadioButton("gender",
					genderOptions.get(g.name()));
			rb.setFormValue(g.name());
			genderPanel.add(rb);
		}

		final TextBox nameField = new TextBox();
		nameField.setFocus(true);

		Grid advancedOptions = new Grid(2, 2);
		advancedOptions.setCellSpacing(6);
		advancedOptions.setHTML(0, 0, constants.nameLabel());
		advancedOptions.setWidget(0, 1, nameField);
		advancedOptions.setHTML(1, 0, constants.genderLabel());
		advancedOptions.setWidget(1, 1, genderPanel);

		final Button createButton = new Button(constants.createButton());

		createButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {

				Gender g = null;
				for (int i = 0, l = genderPanel.getWidgetCount() ; i < l ; i++ ) {
					RadioButton r = (RadioButton) genderPanel.getWidget(i);
					if (r.getValue()) g = Gender.valueOf(r.getFormValue());
				}
				if (g == null) {
					final DialogBox dialogBox = useGenderUnassignedDialogBox();
					dialogBox.center();
					dialogBox.show();
					return;
				}

				AppGameCharacter gc = new AppGameCharacter(nameField.getText(), g);
				appGcServiceAsync.create(gc, new AsyncCallback<AppGameCharacter>() {

					@Override
					public void onFailure(Throwable caught) {
						if (caught instanceof GCNameDuplicateCreateException) {
							messenger.show(constants.impossibleSameName());
						} else if (caught instanceof GCMaxNumberCreateException) {
							messenger.show(constants.maxNumberExceeded());
						} else {
							messenger.show(constants.errorOnLoading());
						}
					}

					@Override
					public void onSuccess(AppGameCharacter result) {
						onCreate(result);
					}

				});
			}

		});

		VerticalPanel allForm = new VerticalPanel();

		allForm.add(advancedOptions);
		allForm.add(createButton);

		// Add advanced options to form in a disclosure panel
		widget.setAnimationEnabled(true);
		widget.ensureDebugId("createGameCharacterPanel");
		widget.setContent(allForm);
	}

	@Override
	protected void onUnload() {
		super.onUnload();
		if (genderUnassignedDialogBox != null) genderUnassignedDialogBox=null;
		// TODO see how to clean the best
	}
	
	private DialogBox useGenderUnassignedDialogBox() {
		if (genderUnassignedDialogBox == null) {
			genderUnassignedDialogBox = new DialogBox();
			genderUnassignedDialogBox.ensureDebugId("genderUnassignedDialogBox");

			// Create a table to layout the content
			VerticalPanel dialogContents = new VerticalPanel();
			dialogContents.setSpacing(4);
			genderUnassignedDialogBox.setWidget(dialogContents);

			// Add some text to the top of the dialog
			HTML details = new HTML(constants.genderUnassigned());
			dialogContents.add(details);
			dialogContents.setCellHorizontalAlignment(details,HasHorizontalAlignment.ALIGN_CENTER);

			// Add a close button at the bottom of the dialog
			Button closeButton = new Button(constants.dialogBoxClose(),
					new ClickHandler() {
				public void onClick(ClickEvent event) {
					genderUnassignedDialogBox.hide();
				}
			});
			dialogContents.add(closeButton);
			if (LocaleInfo.getCurrentLocale().isRTL()) {
				dialogContents.setCellHorizontalAlignment(closeButton,
						HasHorizontalAlignment.ALIGN_LEFT);

			} else {
				dialogContents.setCellHorizontalAlignment(closeButton,
						HasHorizontalAlignment.ALIGN_RIGHT);
			}
		}
		return genderUnassignedDialogBox;
	}

	protected abstract void onCreate(AppGameCharacter result);

}
